package com.imyuanma.qingyun.common.core.concurrent;

import com.imyuanma.qingyun.common.core.concurrent.rejected.QingYunCallerRunsPolicy;
import com.imyuanma.qingyun.common.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 线程池
 *
 * @author wangjy
 * @date 2021/10/16 15:31:52
 */
public class QingYunThreadPoolExecutor extends ThreadPoolExecutor {

    private static final Logger logger = LoggerFactory.getLogger(QingYunThreadPoolExecutor.class);
    /**
     * 线程池记录
     */
    private static final Map<String, QingYunThreadPoolExecutor> THREAD_POOL_MAP = new HashMap<>();
    /**
     * 默认过期时间1分钟
     */
    private static final long DEFAULT_KEEP_ALIVE_TIME = 60L;

    /**
     * 线程池名字
     */
    private String poolName;

    /**
     * 获取所有的线程池
     *
     * @return
     */
    public static List<QingYunThreadPoolExecutor> executorList() {
        return new ArrayList<>(THREAD_POOL_MAP.values());
    }

    /**
     * 获取线程池
     *
     * @param poolName 线程池名字
     * @return
     */
    public static QingYunThreadPoolExecutor get(String poolName) {
        return THREAD_POOL_MAP.get(poolName);
    }

    /**
     * 构建默认配置的线程池
     *
     * @param poolName 线程池名字
     * @return
     */
    public static synchronized QingYunThreadPoolExecutor build(String poolName) {
        return builder(poolName).build();
    }

    /**
     * 构建线程池
     *
     * @param poolName        线程池名字
     * @param corePoolSize    核心线程数
     * @param maximumPoolSize 最大线程数
     * @param workQueue       任务队列
     * @return
     */
    public static synchronized QingYunThreadPoolExecutor build(String poolName, int corePoolSize, int maximumPoolSize, BlockingQueue<Runnable> workQueue) {
        return builder(poolName).corePoolSize(corePoolSize).maximumPoolSize(maximumPoolSize).workQueue(workQueue).build();
    }

    /**
     * 构建线程池
     *
     * @param poolName        线程池名字
     * @param corePoolSize    核心线程数
     * @param maximumPoolSize 最大线程数
     * @param keepAliveTime   过期时间
     * @param unit            时间单位
     * @param workQueue       任务队列
     * @param handler         拒绝策略
     * @return
     */
    public static synchronized QingYunThreadPoolExecutor build(
            String poolName, int corePoolSize, int maximumPoolSize, long keepAliveTime,
            TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        if (StringUtil.isBlank(poolName)) {
            throw new RuntimeException("无效的线程池名字");
        }
        // 禁止线程池名字重复
        if (THREAD_POOL_MAP.containsKey(poolName)) {
            throw new RuntimeException(String.format("已有名为[%s]的线程池,请勿重复创建", poolName));
        }
        // 创建线程池
        QingYunThreadPoolExecutor threadPoolExecutor = new QingYunThreadPoolExecutor(
                corePoolSize, maximumPoolSize, keepAliveTime, unit,
                workQueue, new QingYunThreadFactory(poolName), handler != null ? handler : new QingYunCallerRunsPolicy());
        // 线程池名字
        threadPoolExecutor.poolName = poolName;
        // 放入线程池容器
        THREAD_POOL_MAP.put(poolName, threadPoolExecutor);
        return threadPoolExecutor;
    }

    /**
     * 线程池构造对象
     *
     * @return
     */
    public static Builder builder(String poolName) {
        return new Builder(poolName);
    }

    /**
     * 线程池构造类
     */
    public static class Builder {
        String poolName;
        int corePoolSize = 4;
        int maximumPoolSize = 8;
        long keepAliveTime = DEFAULT_KEEP_ALIVE_TIME;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<>(16);
        RejectedExecutionHandler handler = new QingYunCallerRunsPolicy();

        /**
         * 构造线程池
         *
         * @return
         */
        public QingYunThreadPoolExecutor build() {
            return QingYunThreadPoolExecutor.build(poolName, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        }

        public Builder(String poolName) {
            this.poolName = poolName;
        }

        public Builder corePoolSize(int corePoolSize) {
            this.corePoolSize = corePoolSize;
            return this;
        }

        public Builder maximumPoolSize(int maximumPoolSize) {
            this.maximumPoolSize = maximumPoolSize;
            return this;
        }

        public Builder keepAliveTime(long keepAliveTime, TimeUnit unit) {
            this.keepAliveTime = keepAliveTime;
            this.unit = unit;
            return this;
        }

        public Builder workQueue(BlockingQueue<Runnable> workQueue) {
            this.workQueue = workQueue;
            return this;
        }

        public Builder rejectedHandler(RejectedExecutionHandler handler) {
            this.handler = handler;
            return this;
        }
    }

//    static {
//        // 定时输出线程池信息
//        Executors.newSingleThreadScheduledExecutor()
//                .scheduleAtFixedRate(QingYunThreadPoolExecutor::logAllThreadPoolRuntimeInfo,
//                        30, 180, TimeUnit.SECONDS);
//
//    }

    /**
     * 输出所有线程池的信息
     */
    private static void logAllThreadPoolRuntimeInfo() {
        THREAD_POOL_MAP.values().forEach(QingYunThreadPoolExecutor::logRuntimeInfo);
    }

    /**
     * 输出运行信息
     */
    private void logRuntimeInfo() {
        logger.info("线程池参数打印: 线程池名字:{}, activeCount:{}, completedTaskCount:{}, corePoolSize:{}, aliveTime:{}, largestPoolSize:{}, maximumPoolSize:{}, poolSize:{}, taskCount:{}, queue.size:{}"
                , this.poolName
                , this.getActiveCount()
                , this.getCompletedTaskCount()
                , this.getCorePoolSize()
                , this.getKeepAliveTime(TimeUnit.SECONDS)
                , this.getLargestPoolSize()
                , this.getMaximumPoolSize()
                , this.getPoolSize()
                , this.getTaskCount()
                , this.getQueue().size());
    }


    private QingYunThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    private QingYunThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    private QingYunThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    private QingYunThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    public String getPoolName() {
        return poolName;
    }
}
